import logging
import numpy as np

from util.util_log import setup_logging
from util.util_csv import save_csv
from util.util_image import save_img, save_img_xyz, draw_img
from util.util_ris_pattern import point_2_phi_pattern, phase_2_pattern, phase_2_pattern_xyz, eps, \
    phase_2_bit, phaseBit_2_deg

from multi_beam.multi_beam_QE import qe_beam_N


# 配置日志，默认打印到控制台，也可以设置打印到文件
setup_logging()
# setup_logging(log_file="../../files/logs/multi_beam_BNPA.log")
# 获取日志记录器并记录日志
logger = logging.getLogger("[RIS-multi-beam-BNPA-1bit]")


# ============================================= 核心方法 ======================================
# 将角度映射到 (0, 359)
def normalize_angle(angle):
    """
    将输入的角度转换到0到359度的范围内。
    参数:
    angle (float): 输入的角度值，可以是任意大小的正数或负数。
    返回:
    float: 转换后的角度值，在0到359度之间。
    """
    # 取模运算，确保角度在0到360度之间
    normalized = angle % 360
    # 如果结果正好是360，则返回0
    return normalized if normalized != 360 else 0


def convert_to_clockwise(angles):
    """
    将一个逆时针角度列表转换为对应的顺时针角度列表。
    参数:
    angles (list of float or int): 输入的逆时针角度列表
    返回:
    list of float: 对应的顺时针角度列表
    """
    # 使用列表推导式来计算每个角度的顺时针等效值
    clockwise_angles = [(360 - angle) % 360 for angle in angles]
    return clockwise_angles


# 将 [(theta, phi), ..., ]提取phi, 计算法线角度, 并去重排序
def phi_2_normal_line(angle_list):
    # 1.提取phi
    phi_list = []
    for angle in angle_list:
        phi_list.append(angle[1])
    # 2.提取法线角度
    phi_normal_list = []
    for phi in phi_list:
        normal_1 = normalize_angle(phi + 90)
        normal_2 = normalize_angle(phi - 90)
        if normal_1 not in phi_normal_list:
            phi_normal_list.append(normal_1)
        if normal_2 not in phi_normal_list:
            phi_normal_list.append(normal_2)
    # 3.排序
    phi_normal_list.sort()
    return phi_normal_list


# 以 center 为中心, angles 为届, 分割 shape
def create_mask(shape, center, angles):
    """创建一个掩码，用于标记由三条直线分割的六个区域"""
    h, w = shape
    mask = np.zeros(shape, dtype=np.uint8)
    # 中心点坐标
    cx, cy = center
    #
    for y in range(h):
        for x in range(w):
            # 计算相对于中心点的相对位置
            dx = x - cx
            dy = y - cy
            # 将直角坐标转换为极坐标角度 (以弧度为单位)
            angle = np.arctan2(dy, dx) * 180 / np.pi
            if angle < 0:
                angle += 360  # 确保角度在 [0, 360] 范围内
            # 确定该像素属于哪个区域
            for i, angle_start in enumerate(angles):
                angle_end = angles[(i + 1) % len(angles)]
                if angle_start <= angle < angle_end:
                    mask[y, x] = i + 1
                    break
            else:
                # 如果没有匹配到任何区域（例如，在中心点上），可以指定为0或忽略
                mask[y, x] = 0
    return mask


# 计算 mask 各值的面积
def calculate_areas(mask):
    """计算每个区域的面积"""
    unique, counts = np.unique(mask, return_counts=True)
    areas = dict(zip(unique, counts))
    # 排除背景（通常是0）
    # if 0 in areas:
    #     del areas[0]
    # 如果有需要的话，可以根据image中的实际内容调整面积计算方式
    return areas


def sort_keys_by_values(dict_area):
    """
    根据字典的值对键进行排序，并返回排序后的键列表。

    参数:
        dict_area (dict): 包含键值对的字典。

    返回:
        list: 按照值从大到小排序后的键列表。
    """
    # 使用 sorted 函数和 lambda 表达式根据值对项进行排序，reverse=True 表示降序排列
    sorted_items = sorted(dict_area.items(), key=lambda item: item[1], reverse=True)
    # 提取排序后的键
    sorted_keys = [item[0] for item in sorted_items]
    return sorted_keys


# 根据array_dict，替换array_mask元素
def mask_replace_multiple(array_mask, array_dict):
    """
    根据array_mask中元素的值来替换元素。

    参数:
        array_mask (np.array): 包含1到N整数的二维numpy数组，指示选择哪个数组。
        array_dict (dict): 包含键1到N分别对应array_1到array_N的字典。

    返回:
        np.array: 替换后的结果数组。
    """
    # 确保输入正确
    if not isinstance(array_mask, np.ndarray) or array_mask.ndim != 2:
        raise ValueError("array_mask 必须是二维的 numpy 数组")
    # 检查 array_dict 是否包含所有需要的键，并且对应的数组形状是否一致
    unique_values = np.unique(array_mask)
    if not all(val in array_dict for val in unique_values):
        raise ValueError(f"array_dict 必须包含键 {unique_values}")
    if not all(isinstance(arr, np.ndarray) and arr.shape == array_mask.shape
               for arr in array_dict.values()):
        raise ValueError("array_dict 中的数组必须是与 array_mask 形状相同的 numpy 数组")
    # 初始化结果数组，可以先用其中一个数组初始化
    result = np.zeros_like(array_mask, dtype=array_dict[1].dtype)
    # 使用布尔索引来替换元素
    for key, array in array_dict.items():
        result[array_mask == key] = array[array_mask == key]
    return result


# 生成填空 mask 的列表
def generate_mask_replace(beam_num, list_area_sort_key, phaseBits, phaseBitDefault):
    dict_replace = {}
    for i in range(len(list_area_sort_key)):
        if i < beam_num:
            dict_replace[list_area_sort_key[i]] = phaseBits[i]
        else:
            dict_replace[list_area_sort_key[i]] = phaseBitDefault
    return dict_replace


# ============================================= 主函数 ====================================
# 根据 phaseBit 列表, 按照 QE 合成 phaseBit_mix
def generate_mix_by_qe(list_phaseBits):
    list_phaseBit_mix = []
    for phaseBits in list_phaseBits:
        phaseBit_mix, random_indices = qe_beam_N(phaseBits)
        list_phaseBit_mix.append(phaseBit_mix)
    return list_phaseBit_mix


# mask 每块替代 phaseBit_mix
def phaseBit_mix_replace_mask(list_phaseBit_mix, phase_mask):
    # phaseBit_BNPA = np.zeros_like(phase_mask)
    # todo phase_mask 由 0 至 len(list_phaseBit_mix)-1 的数组成, 将 phaseBit_BNPA 用 list_phaseBit_mix[phase_mix] 对应位置的元素替代
    # 将输入列表转换为 NumPy 数组以确保兼容性
    list_phaseBit_mix = np.array(list_phaseBit_mix)
    # 获取 shape 信息
    num_elements, rows, cols = list_phaseBit_mix.shape
    # 构建索引网格，以便能够正确访问 list_phaseBit_mix 中的元素
    row_indices, col_indices = np.meshgrid(np.arange(rows), np.arange(cols), indexing='ij')
    # 使用 phase_mask 和索引网格来选择对应的值
    phaseBit_BNPA = list_phaseBit_mix[phase_mask, row_indices, col_indices]
    return phaseBit_BNPA


# 核心方法: 双波束
def bnpa_beam_N(bit_num, angles, rows, cols, list_phase_idxs, list_phase_val):
    # 生成切分码阵的 mask
    center = (rows // 2, cols // 2)
    phase_mask = create_mask((rows, cols), center, angles)
    # draw_img(phase_mask)
    # 计算 mask 的面积并排序
    # dict_area = calculate_areas(phase_mask)
    # list_area_sort_key = sort_keys_by_values(dict_area)
    # 建立对应关系
    list_phaseBitMixs = []
    for phase_idxs in list_phase_idxs:
        phaseBitMixs = []
        for i in phase_idxs:
            phaseBitMixs.append(list_phase_val[i])
        list_phaseBitMixs.append(phaseBitMixs)
    # QE 计算 phaseBit_mix
    list_phaseBit_mix = generate_mix_by_qe(list_phaseBitMixs)
    # 根据 dict_replace 将 phaseBits 对应位置元素替代分好区的 mask
    phaseBit_BNPA = phaseBit_mix_replace_mask(list_phaseBit_mix, phase_mask)
    phaseBitDeg_BNPA = phaseBit_2_deg(phaseBit_BNPA, bit_num)
    # draw_img(phaseBit_BNPA)
    # draw_img(phaseBitDeg_BNPA)
    return phaseBit_BNPA, phaseBitDeg_BNPA, list_phaseBit_mix


# BNPA-QE -- 双波束
def main_multi_beam_2(theta1, phi1, theta2, phi2,
                      angles, list_phase_idxs, path_pre, bit_num):
    logger.info("main_multi_beam_2: bit_num=%d, path_pre=%s, " % (bit_num, path_pre))
    logger.info("main_multi_beam_2: angles=%s, " % angles)
    logger.info("main_multi_beam_2: theta1=%d, phi1=%d, theta2=%d, phi2=%d, " % (theta1, phi1, theta2, phi2))
    # 目前只支持2bit
    if bit_num > 2:
        logger.error("main_multi_beam_2: bit_num bigger than 2.")
        return
    phase1, phaseBit1, pattern1 = point_2_phi_pattern(theta1, phi1, bit_num)
    phase2, phaseBit2, pattern2 = point_2_phi_pattern(theta2, phi2, bit_num)
    # BNPA 核心方法
    rows, cols = phaseBit1.shape
    list_phase_val = [phase1, phase2]
    phaseBit_mix, phaseBitDeg_mix, list_phaseBit_mix = bnpa_beam_N(bit_num, angles, rows, cols,
                                                                   list_phase_idxs, list_phase_val)
    # 计算phase_mix的方向图
    phaseBit_mix = np.deg2rad(phaseBitDeg_mix)
    patternBit_mix = phase_2_pattern(phaseBit_mix)
    patternBit_mix_xyz, x, y, z  = phase_2_pattern_xyz(phaseBit_mix)
    #
    # 保存结果
    logger.info("save BNPA multi-beam 2 result...")
    # 保存图片
    save_img(path_pre + "phase1.jpg", phase1)
    save_img(path_pre + "phase2.jpg", phase2)
    save_img(path_pre + "phaseBit1.jpg", phaseBit1)
    save_img(path_pre + "phaseBit2.jpg", phaseBit2)
    save_img(path_pre + "pattern1.jpg", pattern1)
    save_img(path_pre + "pattern2.jpg", pattern2)
    save_img(path_pre + "phaseBit_mix.jpg", phaseBit_mix)         # BNPA -- 结果码阵
    save_img(path_pre + "patternBit_mix.jpg", patternBit_mix)     # BNPA -- 结果码阵方向图
    save_img_xyz(path_pre + "patternBit_mix_xyz.jpg", np.abs(patternBit_mix_xyz), x, y)
    # 保存相位结果
    save_csv(phase1, path_pre + "phase1.csv")
    save_csv(phase2, path_pre + "phase2.csv")
    save_csv(phaseBit1, path_pre + "phaseBit1.csv")
    save_csv(phaseBit2, path_pre + "phaseBit2.csv")
    save_csv(phaseBit_mix, path_pre + "phaseBit_mix.csv")


# BNPA-QE -- 四波束
def main_multi_beam_4(theta1, phi1, theta2, phi2, theta3, phi3, theta4, phi4,
                      angles, list_phase_idxs, path_pre, bit_num):
    logger.info("main_multi_beam_4: bit_num=%d, path_pre=%s, " % (bit_num, path_pre))
    logger.info("main_multi_beam_4: angles=%s, " % angles)
    logger.info("main_multi_beam_4: theta1=%d, phi1=%d, theta2=%d, phi2=%d, theta3=%d, phi3=%d, theta4=%d, phi4=%d"
                % (theta1, phi1, theta2, phi2, theta3, phi3, theta4, phi4))
    phase1, phaseBit1, pattern1 = point_2_phi_pattern(theta1, phi1, bit_num)
    phase2, phaseBit2, pattern2 = point_2_phi_pattern(theta2, phi2, bit_num)
    phase3, phaseBit3, pattern3 = point_2_phi_pattern(theta3, phi3, bit_num)
    phase4, phaseBit4, pattern4 = point_2_phi_pattern(theta4, phi4, bit_num)
    # 确保所有数组具有相同的形状
    assert phaseBit1.shape == phaseBit2.shape == phaseBit3.shape == phaseBit4.shape, "所有数组必须具有相同的形状"
    # BNPA 核心方法
    rows, cols = phaseBit1.shape
    list_phase_val = [phaseBit1, phaseBit2, phaseBit3, phaseBit4]
    phaseBit_mix, phaseBitDeg_mix, list_phaseBit_mix_qe = bnpa_beam_N(bit_num, angles, rows, cols,
                                                                      list_phase_idxs, list_phase_val)
    # 计算phase_mix的方向图
    phaseBit_mix = np.deg2rad(phaseBitDeg_mix)
    patternBit_mix = phase_2_pattern(phaseBit_mix)
    #
    # 保存结果
    logger.info("save BNPA-QE multi-beam 4 result...")
    patternBit_mix_xyz, x, y, z = phase_2_pattern_xyz(phaseBit_mix)
    #
    for i in range(len(list_phaseBit_mix_qe)):
        phaseBit_mix_qe = list_phaseBit_mix_qe[i]
        phaseBit_mix_qe_name = "phaseBit_mix_qe_" + str(i) + ".jpg"
        save_img(path_pre + phaseBit_mix_qe_name, phaseBit_mix_qe)
    # 保存图片
    save_img(path_pre + "phase1.jpg", phase1)
    save_img(path_pre + "phase2.jpg", phase2)
    save_img(path_pre + "phase3.jpg", phase3)
    save_img(path_pre + "phase4.jpg", phase4)
    save_img(path_pre + "phaseBit1.jpg", phaseBit1)
    save_img(path_pre + "phaseBit2.jpg", phaseBit2)
    save_img(path_pre + "phaseBit3.jpg", phaseBit3)
    save_img(path_pre + "phaseBit4.jpg", phaseBit4)
    save_img(path_pre + "pattern1.jpg", pattern1)
    save_img(path_pre + "pattern2.jpg", pattern2)
    save_img(path_pre + "pattern3.jpg", pattern3)
    save_img(path_pre + "pattern4.jpg", pattern4)
    save_img(path_pre + "phaseBit_mix.jpg", phaseBit_mix)  # 相位合成法 -- 结果码阵
    save_img(path_pre + "patternBit_mix.jpg", patternBit_mix)  # 相位合成法 -- 结果码阵方向图
    save_img_xyz(path_pre + "patternBit_mix_xyz.jpg", np.abs(patternBit_mix_xyz), x, y)
    # 保存相位结果
    save_csv(phase1, path_pre + "phase1.csv")
    save_csv(phase2, path_pre + "phase2.csv")
    save_csv(phase3, path_pre + "phase3.csv")
    save_csv(phase4, path_pre + "phase4.csv")
    save_csv(phaseBit1, path_pre + "phaseBit1.csv")
    save_csv(phaseBit2, path_pre + "phaseBit2.csv")
    save_csv(phaseBit3, path_pre + "phaseBit3.csv")
    save_csv(phaseBit4, path_pre + "phaseBit4.csv")
    save_csv(phaseBit_mix, path_pre + "phaseBit_mix.csv")


# BNPA-QE -- 八波束
def main_multi_beam_8(theta1, phi1, theta2, phi2, theta3, phi3, theta4, phi4,
                      theta5, phi5, theta6, phi6, theta7, phi7, theta8, phi8,
                      angles, list_phase_idxs, path_pre, bit_num):
    logger.info("main_multi_beam_8: bit_num=%d, path_pre=%s, " % (bit_num, path_pre))
    logger.info("main_multi_beam_8: angles=%s, " % angles)
    logger.info("main_multi_beam_8: theta1=%d, phi1=%d, theta2=%d, phi2=%d, theta3=%d, phi3=%d, theta4=%d, phi4=%d"
                % (theta1, phi1, theta2, phi2, theta3, phi3, theta4, phi4))
    logger.info("main_multi_beam_8: theta5=%d, phi5=%d, theta6=%d, phi6=%d, theta7=%d, phi7=%d, theta8=%d, phi8=%d"
                % (theta5, phi5, theta6, phi6, theta7, phi7, theta8, phi8))
    phase1, phaseBit1, pattern1 = point_2_phi_pattern(theta1, phi1, bit_num)
    phase2, phaseBit2, pattern2 = point_2_phi_pattern(theta2, phi2, bit_num)
    phase3, phaseBit3, pattern3 = point_2_phi_pattern(theta3, phi3, bit_num)
    phase4, phaseBit4, pattern4 = point_2_phi_pattern(theta4, phi4, bit_num)
    phase5, phaseBit5, pattern5 = point_2_phi_pattern(theta5, phi5, bit_num)
    phase6, phaseBit6, pattern6 = point_2_phi_pattern(theta6, phi6, bit_num)
    phase7, phaseBit7, pattern7 = point_2_phi_pattern(theta7, phi7, bit_num)
    phase8, phaseBit8, pattern8 = point_2_phi_pattern(theta8, phi8, bit_num)
    # 确保所有数组具有相同的形状
    assert phaseBit1.shape == phaseBit2.shape == phaseBit3.shape == phaseBit4.shape, "所有数组必须具有相同的形状"
    # BNPA 核心方法
    rows, cols = phaseBit1.shape
    list_phase_val = [phaseBit1, phaseBit2, phaseBit3, phaseBit4, phaseBit5, phaseBit6, phaseBit7, phaseBit8]
    phaseBit_mix, phaseBitDeg_mix, list_phaseBit_mix_qe = bnpa_beam_N(bit_num, angles, rows, cols,
                                                                      list_phase_idxs, list_phase_val)
    # 计算phase_mix的方向图
    phaseBit_mix = np.deg2rad(phaseBitDeg_mix)
    patternBit_mix = phase_2_pattern(phaseBit_mix)
    #
    # 保存结果
    logger.info("save BNPA-QE multi-beam 8 result...")
    patternBit_mix_xyz, x, y, z = phase_2_pattern_xyz(phaseBit_mix)
    #
    for i in range(len(list_phaseBit_mix_qe)):
        phaseBit_mix_qe = list_phaseBit_mix_qe[i]
        phaseBit_mix_qe_name = "phaseBit_mix_qe_" + str(i) + ".jpg"
        save_img(path_pre + phaseBit_mix_qe_name, phaseBit_mix_qe)
    # 保存图片
    save_img(path_pre + "phase1.jpg", phase1)
    save_img(path_pre + "phase2.jpg", phase2)
    save_img(path_pre + "phase3.jpg", phase3)
    save_img(path_pre + "phase4.jpg", phase4)
    save_img(path_pre + "phase5.jpg", phase5)
    save_img(path_pre + "phase6.jpg", phase6)
    save_img(path_pre + "phase7.jpg", phase7)
    save_img(path_pre + "phase8.jpg", phase8)
    save_img(path_pre + "phaseBit1.jpg", phaseBit1)
    save_img(path_pre + "phaseBit2.jpg", phaseBit2)
    save_img(path_pre + "phaseBit3.jpg", phaseBit3)
    save_img(path_pre + "phaseBit4.jpg", phaseBit4)
    save_img(path_pre + "phaseBit5.jpg", phaseBit5)
    save_img(path_pre + "phaseBit6.jpg", phaseBit6)
    save_img(path_pre + "phaseBit7.jpg", phaseBit7)
    save_img(path_pre + "phaseBit8.jpg", phaseBit8)
    save_img(path_pre + "pattern1.jpg", pattern1)
    save_img(path_pre + "pattern2.jpg", pattern2)
    save_img(path_pre + "pattern3.jpg", pattern3)
    save_img(path_pre + "pattern4.jpg", pattern4)
    save_img(path_pre + "pattern5.jpg", pattern5)
    save_img(path_pre + "pattern6.jpg", pattern6)
    save_img(path_pre + "pattern7.jpg", pattern7)
    save_img(path_pre + "pattern8.jpg", pattern8)
    save_img(path_pre + "phaseBit_mix.jpg", phaseBit_mix)  # 相位合成法 -- 结果码阵
    save_img(path_pre + "patternBit_mix.jpg", patternBit_mix)  # 相位合成法 -- 结果码阵方向图
    save_img_xyz(path_pre + "patternBit_mix_xyz.jpg", np.abs(patternBit_mix_xyz), x, y)
    # 保存相位结果
    save_csv(phase1, path_pre + "phase1.csv")
    save_csv(phase2, path_pre + "phase2.csv")
    save_csv(phase3, path_pre + "phase3.csv")
    save_csv(phase4, path_pre + "phase4.csv")
    save_csv(phase5, path_pre + "phase5.csv")
    save_csv(phase6, path_pre + "phase6.csv")
    save_csv(phase7, path_pre + "phase7.csv")
    save_csv(phase8, path_pre + "phase8.csv")
    save_csv(phaseBit1, path_pre + "phaseBit1.csv")
    save_csv(phaseBit2, path_pre + "phaseBit2.csv")
    save_csv(phaseBit3, path_pre + "phaseBit3.csv")
    save_csv(phaseBit4, path_pre + "phaseBit4.csv")
    save_csv(phaseBit5, path_pre + "phaseBit5.csv")
    save_csv(phaseBit6, path_pre + "phaseBit6.csv")
    save_csv(phaseBit7, path_pre + "phaseBit7.csv")
    save_csv(phaseBit8, path_pre + "phaseBit8.csv")
    save_csv(phaseBit_mix, path_pre + "phaseBit_mix.csv")


# BNPA-QE -- N波束
def main_multi_beam_N(points, angles, list_phase_idxs, path_pre, bit_num):
    logger.info("main_multi_beam_N: bit_num=%d, path_pre=%s, " % (bit_num, path_pre))
    logger.info("main_multi_beam_N: num of points = %d" % (len(points)))
    logger.info("main_multi_beam_N: points = %s" % (points))
    phase_pattern_list = []
    phaseBit_list = []
    for point in points:
        theta = point[0]
        phi = point[1]
        phase, phaseBit, pattern = point_2_phi_pattern(theta, phi, bit_num)
        phase_pattern_list.append([phase, phaseBit, pattern])
        phaseBit_list.append(phaseBit)
    # BNPA 核心方法
    rows, cols = phaseBit_list[0].shape
    phaseBit_mix, phaseBitDeg_mix, list_phaseBit_mix_qe = bnpa_beam_N(bit_num, angles, rows, cols,
                                                                      list_phase_idxs, phaseBit_list)
    # 计算phase_mix的方向图
    phaseBit_mix = np.deg2rad(phaseBitDeg_mix)
    patternBit_mix = phase_2_pattern(phaseBit_mix)
    #
    # 保存结果
    logger.info("save BNPA-QE multi-beam 8 result...")
    patternBit_mix_xyz, x, y, z = phase_2_pattern_xyz(phaseBit_mix)
    # 保存 QE 结果
    for i in range(len(list_phaseBit_mix_qe)):
        phaseBit_mix_qe = list_phaseBit_mix_qe[i]
        phaseBit_mix_qe_name = "phaseBit_mix_qe_" + str(i) + ".jpg"
        save_img(path_pre + phaseBit_mix_qe_name, phaseBit_mix_qe)
    # 保存结果
    for i in range(len(phase_pattern_list)):
        phase = phase_pattern_list[i][0]
        phaseBit = phase_pattern_list[i][1]
        pattern = phase_pattern_list[i][2]
        # 保存图片
        save_img(path_pre + "phase" + str(i + 1) + ".jpg", phase)
        save_img(path_pre + "phaseBit" + str(i + 1) + ".jpg", phaseBit)
        save_img(path_pre + "pattern" + str(i + 1) + ".jpg", pattern)
        # 保存相位结果
        save_csv(phase, path_pre + "phase" + str(i + 1) + ".csv")
        save_csv(phaseBit, path_pre + "phaseBit" + str(i + 1) + ".csv")
    # 保存图片
    save_img(path_pre + "phaseBit_mix.jpg", phaseBit_mix)       # BNPA-QE -- 结果码阵
    save_img(path_pre + "patternBit_mix.jpg", patternBit_mix)   # BNPA-QE -- 结果码阵方向图
    save_img_xyz(path_pre + "patternBit_mix_xyz.jpg", np.abs(patternBit_mix_xyz), x, y)
    # 保存相位结果
    save_csv(phaseBit_mix, path_pre + "phaseBit_mix.csv")



# =============================================== 主函数 ================================================
# 主函数 --均匀分区
def main_multi_bnpa_qe():
    # 四波束 (0, 60, 120, 180) 参数
    # angles = [30, 90, 150, 210, 270, 330]
    # list_phase_idxs = [[0, 1, 2],
    #                    [0, 2],
    #                    [2, 3],
    #                    [3],
    #                    [1, 3],
    #                    [0, 1]]
    # 四波束 (0, 90, 180, 270) 参数
    # angles = [0, 90, 180, 270]
    # list_phase_idxs = [[2, 3],
    #                    [1, 2],
    #                    [0, 1],
    #                    [3, 0]]
    # 八波束 (0, 45, 90, 135, 180, 225, 270, 315) 参数
    # angles = [0, 45, 90, 135, 180, 225, 270, 315]
    # list_phase_idxs = [[7, 0, 1, 2],
    #                    [6, 7, 0, 1],
    #                    [5, 6, 7, 0],
    #                    [4, 5, 6, 7],
    #                    [3, 4, 5, 6],
    #                    [2, 3, 4, 5],
    #                    [1, 2, 3, 4],
    #                    [0, 1, 2, 3]]
    # # 16波束 (0, 22.5, 45, 67.5, 90, 112.5, 135, 157.5, 180, 202.5, 225, 247.5, 270, 292.5, 315, 337.5) 参数
    # angles = [0, 22.5, 45, 67.5, 90, 112.5, 135, 157.5, 180, 202.5, 225, 247.5, 270, 292.5, 315, 337.5]
    # list_phase_idxs = [[13, 14, 15,  0,  1,  2,  3,  4],
    #                    [12, 13, 14, 15,  0,  1,  2,  3],
    #                    [11, 12, 13, 14, 15,  0,  1,  2],
    #                    [10, 11, 12, 13, 14, 15,  0,  1],
    #                    [ 9, 10, 11, 12, 13, 14, 15,  0],
    #                    [ 8,  9, 10, 11, 12, 13, 14, 15],
    #                    [ 7,  8,  9, 10, 11, 12, 13, 14],
    #                    [ 6,  7,  8,  9, 10, 11, 12, 13],
    #                    [ 5,  6,  7,  8,  9, 10, 11, 12],
    #                    [ 4,  5,  6,  7,  8,  9, 10, 11],
    #                    [ 3,  4,  5,  6,  7,  8,  9, 10],
    #                    [ 2,  3,  4,  5,  6,  7,  8,  9],
    #                    [ 1,  2,  3,  4,  5,  6,  7,  8],
    #                    [ 0,  1,  2,  3,  4,  5,  6,  7],
    #                    [15,  0,  1,  2,  3,  4,  5,  6],
    #                    [14, 15,  0,  1,  2,  3,  4,  5]]
    # # 查看分区
    # rows, cols = 64, 64
    # center = (rows // 2, cols // 2)
    # phase_mask = create_mask((rows, cols), center, angles)
    # draw_img(phase_mask)
    # print("phase_mask:")
    # print(phase_mask)
    #
    # main_multi_beam_2(30, 0, 30, 90, angles,
    #                   [],
    #                   "../files/multi-beam/1bit/BNPA-QE/2-(30,0,30,90)/", 1)
    # main_multi_beam_4(30, 0, 30, 60, 30, 120, 30, 180, [30, 90, 150, 210, 270, 330],
    #                   [[0, 1, 2], [0, 2], [2, 3], [3], [1, 3], [0, 1]],
    #                   "../files/multi-beam/1bit/BNPA-QE/4-(30,0,30,60,30,120,30,180)/", 1)
    # main_multi_beam_4(30, 0, 30, 90, 30, 180, 30, 270, [0, 90, 180, 270],
    #                   [[2, 3], [1, 2], [0, 1], [3, 0]],
    #                   "../files/multi-beam/1bit/BNPA-QE/4-(30,0,30,90,30,180,30,270)/", 1)
    # main_multi_beam_8(30, 0, 30, 45, 30, 90, 30, 135, 30, 180, 30, 225, 30, 270, 30, 315,
    #                   [0, 45, 90, 135, 180, 225, 270, 315],
    #                   [[7, 0, 1, 2], [6, 7, 0, 1], [5, 6, 7, 0], [4, 5, 6, 7],
    #                    [3, 4, 5, 6], [2, 3, 4, 5], [1, 2, 3, 4], [0, 1, 2, 3]],
    #                   "../files/multi-beam/1bit/BNPA-QE/8-(30,45step)/", 1)
    main_multi_beam_N([[30, 0], [30, 22.5], [30, 45], [30, 67.5], [30, 90], [30, 112.5], [30, 135], [30, 157.5],
                       [30, 180], [30, 202.5], [30, 225], [30, 247.5], [30, 270], [30, 292.5], [30, 315], [30, 337.5]],
                      [0, 22.5, 45, 67.5, 90, 112.5, 135, 157.5, 180, 202.5, 225, 247.5, 270, 292.5, 315, 337.5],
                      [[13, 14, 15, 0, 1, 2, 3, 4], [12, 13, 14, 15, 0, 1, 2, 3],
                       [11, 12, 13, 14, 15, 0, 1, 2], [10, 11, 12, 13, 14, 15, 0, 1],
                       [9, 10, 11, 12, 13, 14, 15, 0], [8, 9, 10, 11, 12, 13, 14, 15],
                       [7, 8, 9, 10, 11, 12, 13, 14], [6, 7, 8, 9, 10, 11, 12, 13],
                       [5, 6, 7, 8, 9, 10, 11, 12], [4, 5, 6, 7, 8, 9, 10, 11],
                       [3, 4, 5, 6, 7, 8, 9, 10], [2, 3, 4, 5, 6, 7, 8, 9],
                       [1, 2, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 5, 6, 7],
                       [15, 0, 1, 2, 3, 4, 5, 6], [14, 15, 0, 1, 2, 3, 4, 5]],
                      "../files/multi-beam/1bit/BNPA-QE/16-(30,22.5step)/", 1)
    #
    # main_multi_beam_4(30, 0, 30, 60, 30, 120, 30, 180, [30, 90, 150, 210, 270, 330],
    #                   [[0, 1, 2], [0, 2], [2, 3], [3], [1, 3], [0, 1]],
    #                   "../files/multi-beam/2bit/BNPA-QE/4-(30,0,30,60,30,120,30,180)/", 2)
    # main_multi_beam_4(30, 0, 30, 90, 30, 180, 30, 270, [0, 90, 180, 270],
    #                   [[2, 3], [1, 2], [0, 1], [3, 0]],
    #                   "../files/multi-beam/2bit/BNPA-QE/4-(30,0,30,90,30,180,30,270)/", 2)
    # main_multi_beam_8(30, 0, 30, 45, 30, 90, 30, 135, 30, 180, 30, 225, 30, 270, 30, 315,
    #                   [0, 45, 90, 135, 180, 225, 270, 315],
    #                   [[7, 0, 1, 2], [6, 7, 0, 1], [5, 6, 7, 0], [4, 5, 6, 7],
    #                    [3, 4, 5, 6], [2, 3, 4, 5], [1, 2, 3, 4], [0, 1, 2, 3]],
    #                   "../files/multi-beam/2bit/BNPA-QE/8-(30,45step)/", 2)
    main_multi_beam_N([[30, 0], [30, 22.5], [30, 45], [30, 67.5], [30, 90], [30, 112.5], [30, 135], [30, 157.5],
                       [30, 180], [30, 202.5], [30, 225], [30, 247.5], [30, 270], [30, 292.5], [30, 315], [30, 337.5]],
                      [0, 22.5, 45, 67.5, 90, 112.5, 135, 157.5, 180, 202.5, 225, 247.5, 270, 292.5, 315, 337.5],
                      [[13, 14, 15, 0, 1, 2, 3, 4], [12, 13, 14, 15, 0, 1, 2, 3],
                       [11, 12, 13, 14, 15, 0, 1, 2], [10, 11, 12, 13, 14, 15, 0, 1],
                       [9, 10, 11, 12, 13, 14, 15, 0], [8, 9, 10, 11, 12, 13, 14, 15],
                       [7, 8, 9, 10, 11, 12, 13, 14], [6, 7, 8, 9, 10, 11, 12, 13],
                       [5, 6, 7, 8, 9, 10, 11, 12], [4, 5, 6, 7, 8, 9, 10, 11],
                       [3, 4, 5, 6, 7, 8, 9, 10], [2, 3, 4, 5, 6, 7, 8, 9],
                       [1, 2, 3, 4, 5, 6, 7, 8], [0, 1, 2, 3, 4, 5, 6, 7],
                       [15, 0, 1, 2, 3, 4, 5, 6], [14, 15, 0, 1, 2, 3, 4, 5]],
                      "../files/multi-beam/2bit/BNPA-QE/16-(30,22.5step)/", 2)


# 主函数 - 非均匀分区
def main_multi_bnpa_qe_nonuniform():
    # part 0: 参数
    # 四波束 (83,230),(65,93),(13,138),(25,156) 参数
    # angle_list = [[83, 230], [65, 93], [13, 138], [25, 156]]
    # list_phase_idxs = [[0, 1, 3],
    #                    [1, 3],
    #                    [1, 3],
    #                    [1],
    #                    [2],
    #                    [0, 2],
    #                    [0, 2],
    #                    [0, 2, 3]]
    # path_dir = "../files/multi-beam-scan/1bit/rand-4/BNPA-QE/"
    # 七波束 (30,110),(12,286),(48,273),(48,133),(57,135),(45,167),(85,204) 参数
    # angle_list = [(30,110),(12,286),(48,273),(48,133),(57,135),(45,167),(85,204)]
    # list_phase_idxs = [[0, 5, 6, 1],
    #                    [0, 5, 1],
    #                    [0, 1],
    #                    [0, 4, 1],
    #                    [0, 4, 1, 3],
    #                    [0, 4, 3],
    #                    [0, 2, 4, 3],
    #                    [2, 4, 3],
    #                    [6, 2, 4, 3],
    #                    [6, 5, 2, 4, 3],
    #                    [6, 5, 2, 3],
    #                    [6, 5, 2],
    #                    [6, 5, 1, 2],
    #                    [6, 5, 1]]
    # path_dir = "../files/multi-beam-scan/1bit/rand-7/BNPA-QE/"
    # 八波束 (22,50),(56,349),(5,142),(85,54),(61,327),(61,195),(80,153),(2,336) 参数
    # angle_list = [(22,50),(56,349),(5,142),(85,54),(61,327),(61,195),(80,153),(2,336)]
    angle_list = [(22,50),(85,54),(5,142),(80,153),(61,195),(61,327),(2,336),(56,349)]
    list_phase_idxs = [[1, 2, 4, 5],
                       [0, 1, 2, 4, 5],
                       [0, 2, 4, 5],
                       [0, 4, 5],
                       [0, 3, 4, 5],
                       [0, 3, 5],
                       [0, 3],
                       [0, 3, 6],
                       [0, 3, 6, 7],
                       [3, 6, 7],
                       [1, 3, 6, 7],
                       [1, 2, 3, 6, 7],
                       [1, 2, 6, 7],
                       [1, 2, 4, 6, 7],
                       [1, 2, 4, 5, 6, 7],
                       [1, 2, 4, 5, 7]]
    path_dir = "../files/multi-beam-scan/1bit/rand-8/BNPA-QE/"
    # 16波束 (13,70),(51,319),(35,103),(50,218),(63,148),(71,267),(75,196),(67,275),
    #       (20,32),(59,80),(20,355),(2,336),(0,81),(83,48),(3,269),(14,276) 参数
    #
    # part 1: 查看分区
    # 1.1 转换角度
    # 生成对应的法向角度
    angles = phi_2_normal_line(angle_list)
    print("angles:", angles)
    # 貌似正逆时针问题, 转换一下
    convert_angles = convert_to_clockwise(angles)
    print("convert_angles:", convert_angles)
    # create_mask需要递增的, 反转一下
    convert_angles.reverse()
    print("convert_angles:", convert_angles)
    # 1.2 生成分区
    # rows, cols = 64, 64
    # center = (rows // 2, cols // 2)
    # phase_mask = create_mask((rows, cols), center, convert_angles)
    # draw_img(phase_mask)
    # print("phase_mask:")
    # print(phase_mask)
    #
    # part2. BNPA
    main_multi_beam_N(angle_list, convert_angles, list_phase_idxs, path_dir, 1)



# ============================================= 测试函数 ====================================
def test_phaseBit_mix_replace_mask():
    list_phaseBit_mix = [
        np.array([[1, 2], [3, 4]]),
        np.array([[11, 12], [13, 14]]),
        np.array([[21, 22], [23, 24]])
    ]
    phase_mask = np.array([[0, 1], [2, 0]])
    output = phaseBit_mix_replace_mask(list_phaseBit_mix, phase_mask)
    print(output)  # 应输出 [[1, 12], [23, 4]]


def test_normalize_angle():
    test_angles = [720, -1440, 180, -90, 450, -45, -15.5]
    for angle in test_angles:
        print(f"原始角度: {angle}, 转换后角度: {normalize_angle(angle)}")


def test_phi_2_normal_line():
    # angle_list = [(30, 0), (30, 60), (30, 120), (30, 180)]
    # angle_list = [(30, 0), (30, 90), (30, 180), (30, 270)]
    # angle_list = [(30, 0), (30, 45), (30, 90), (30, 135), (30, 180), (30, 225), (30, 270), (30, 315)]
    angle_list = [(83, 230), (65, 93), (13, 138), (25, 156)]
    phi_normal_list = phi_2_normal_line(angle_list)
    print("phi_normal_list:", phi_normal_list)




if __name__ == '__main__':
    logger.info("1bit-RIS-multi-beam-BNPA: Beam Normal Partitioning Algorithm")
    # main_multi_bnpa_qe()
    main_multi_bnpa_qe_nonuniform()
    # 测试函数
    # test_phaseBit_mix_replace_mask()
    # test_normalize_angle()
    # test_phi_2_normal_line()